package cn.stylefeng.guns.modular.gridsystem.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.StrFormatter;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.stylefeng.guns.core.context.constant.ConstantContextHolder;
import cn.stylefeng.guns.core.context.login.LoginContextHolder;
import cn.stylefeng.guns.core.exception.ServiceException;
import cn.stylefeng.guns.core.exception.enums.StatusExceptionEnum;
import cn.stylefeng.guns.core.factory.PageFactory;
import cn.stylefeng.guns.core.pojo.page.PageResult;
import cn.stylefeng.guns.core.util.HttpClientUtil;
import cn.stylefeng.guns.modular.gridsystem.constants.*;
import cn.stylefeng.guns.modular.gridsystem.entity.*;
import cn.stylefeng.guns.modular.gridsystem.enums.GatewayExceptionEnum;
import cn.stylefeng.guns.modular.gridsystem.listener.GatewayImportListener;
import cn.stylefeng.guns.modular.gridsystem.mapper.*;
import cn.stylefeng.guns.modular.gridsystem.model.param.ApplicationRecordParam;
import cn.stylefeng.guns.modular.gridsystem.model.param.BizGatewayParam;
import cn.stylefeng.guns.modular.gridsystem.model.param.BizGatewayScheduleParam;
import cn.stylefeng.guns.modular.gridsystem.model.param.GatewayImportParam;
import cn.stylefeng.guns.modular.gridsystem.model.result.*;
import cn.stylefeng.guns.modular.gridsystem.mqtt.result.GatewayChannelStatus;
import cn.stylefeng.guns.modular.gridsystem.service.*;
import cn.stylefeng.guns.sys.modular.file.entity.SysFileInfo;
import cn.stylefeng.guns.sys.modular.file.service.SysFileInfoService;
import com.alibaba.excel.EasyExcel;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.io.FileSystemResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.File;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 采集设备 服务实现类
 *
 * @author ssy
 * @date 2021/09/14 11:47
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class BizGatewayServiceImpl extends ServiceImpl<BizGatewayMapper, BizGateway> implements BizGatewayService {

    private final BizGatewayConfigService gatewayConfigService;

    private final GatewaySceneService sceneService;

    private final GatewaySceneConfigMapper sceneConfigMapper;

    private final BizGatewayConfigTemplateMapper configTemplateMapper;

    private final BizGatewayTypeMapper gatewayTypeMapper;

    private final BizChannelTypeMapper channelTypeMapper;

    private final BizGatewayChannelMapper gatewayChannelMapper;

    private final BizThreholdItemMapper threholdItemMapper;

    private final BizGatewayChannelMapper channelMapper;

    private final GatewayTaskService taskService;

    private final BizStationMapper stationMapper;

    private final BizGatewayScheduleMapper scheduleMapper;

    private final BizCollectorConfigMapper collectorConfigMapper;

    private final SoundCardService soundCardService;

    private final SysFileInfoService fileInfoService;

    private final BizExceptionService exceptionService;

    private final BizGatewayScheduleService gatewayScheduleService;

    @Override
    public PageResult<BizGatewayResult> page(BizGatewayParam bizGatewayParam) {
        // 查询分页结果
        return new PageResult<>(this.baseMapper.pageResult(PageFactory.defaultPage(), bizGatewayParam));
    }

    @Override
    public PageResult<BizGatewayResult> guidePage(BizGatewayParam param) {
        // 查询分页结果
        return new PageResult<>(this.baseMapper.guidePageResult(PageFactory.defaultPage(), param));
    }

    @Override
    public List<GatewayResult> list(BizGatewayParam bizGatewayParam) {

        // 构造条件
        LambdaQueryWrapper<BizGateway> queryWrapper = new LambdaQueryWrapper<>();
        if (ObjectUtil.isNotNull(bizGatewayParam)) {
            if (ObjectUtil.isNotEmpty(bizGatewayParam.getStationId())) {
                queryWrapper.eq(BizGateway::getStationId, bizGatewayParam.getStationId());
            }
        }
        queryWrapper.orderByDesc(BizGateway::getCreateTime);
        List<GatewayResult> gatewayList = this.list(queryWrapper).stream().map(item -> BeanUtil.toBean(item, GatewayResult.class)).collect(Collectors.toList());

        // 查询是否包含未处理的故障并设置到响应结果当中
        for (GatewayResult gateway : gatewayList) {
            gateway.setHasNoHandleException(exceptionService.count(new LambdaQueryWrapper<BizException>()
                    .eq(BizException::getGatewayCode, gateway.getGatewayCode())
                    .eq(BizException::getStatus, "0")) > 0);
        }

        return gatewayList;
    }

    @Override
    public List<BizGateway> listAll(BizGatewayParam param) {

        // 当前登录人所在部门下的所有站点
        List<BizStation> stations = stationMapper.selectList(new LambdaQueryWrapper<BizStation>().eq(BizStation::getOrgId, LoginContextHolder.me().getSysLoginUserOrgId()));

        if (ObjectUtil.isEmpty(stations)) {
            return null;
        }

        return this.list(new LambdaQueryWrapper<BizGateway>().in(BizGateway::getStationId, stations.stream().map(BizStation::getId).collect(Collectors.toList())));
    }

    @Override
    public List<BizGatewayResult> listNoGrant(BizGatewayParam param) {
        return this.list(new LambdaQueryWrapper<BizGateway>()
                .eq(ObjectUtil.isNotEmpty(param.getStationId()), BizGateway::getStationId, param.getStationId())
                .and(w -> {
                    // 待申请
                    w.eq(BizGateway::getGrantStatus, GatewayGrantStatusConstant.WAIT_APPLY)
                            .or()
                            // 审核失败
                            .eq(BizGateway::getGrantStatus, GatewayGrantStatusConstant.AUDIT_FAILED)
                            .or()
                            // 授权到期
                            .eq(BizGateway::getGrantStatus, GatewayGrantStatusConstant.GRANT_EXPIRED);
                })
                .orderByDesc(BizGateway::getCreatedAt))
                .stream()
                .map(item -> BeanUtil.toBean(item, BizGatewayResult.class))
                .collect(Collectors.toList());
    }

    @Override
    public BizGateway listByDeviceCode(String deviceCode) {
        LambdaQueryWrapper<BizGateway> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BizGateway::getGatewayCode, deviceCode);
        return this.baseMapper.selectOne(queryWrapper);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(BizGatewayParam param) {

        // 1、检查编码是否存在
        if (count(new LambdaQueryWrapper<BizGateway>().eq(BizGateway::getGatewayCode, param.getGatewayCode())) > 0) {
            log.warn("网关编号已存在，网关编号为：{}", param.getGatewayCode());
            throw new ServiceException(GatewayExceptionEnum.GATEWAY_CODE_EXIST);
        }

        BizGateway gateway = BeanUtil.toBean(param, BizGateway.class);
        param.setCreatedAt(DateUtil.now());
        param.setDataReportingSwitch(DataReportingConstant.ON);

        // 3、保存网关信息
        save(gateway);

        // 4、初始化网关配置
        initGatewayConfig(gateway.getId(), param.getSceneId());

        //默认设置采集时间为全天
        BizGatewayScheduleParam bizGatewayScheduleParam = new BizGatewayScheduleParam();
        bizGatewayScheduleParam.setGatewayId(gateway.getId());
        bizGatewayScheduleParam.setTimeSchedule(BizGatewayConstant.GATEWAY_AUDIO_SCHEDULE);
        gatewayScheduleService.add(bizGatewayScheduleParam);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addGateway(BizGatewayParam param) {

        // 1、检查编码是否存在
        if (count(new LambdaQueryWrapper<BizGateway>().eq(BizGateway::getGatewayCode, param.getGatewayCode())) > 0) {
            log.warn("网关编号已存在，网关编号为：{}", param.getGatewayCode());
            throw new ServiceException(GatewayExceptionEnum.GATEWAY_CODE_EXIST);
        }

        // 2、检查关联站点是否存在
        BizStation station = stationMapper.selectById(param.getStationId());
        if (ObjectUtil.isEmpty(station)) {
            log.warn("关联站点不存在，站点主键为：{}", param.getStationId());
            throw new ServiceException(GatewayExceptionEnum.STATION_NOT_EXIST);
        }

        BizGateway gateway = BeanUtil.toBean(param, BizGateway.class);
        param.setCreatedAt(DateUtil.now());
        param.setDataReportingSwitch(DataReportingConstant.ON);

        // 3、保存网关信息
        this.save(gateway);
        Integer gatewayId = gateway.getId();

        // 4、初始化网关配置
        this.initGatewayConfig(gateway.getId(), param.getSceneId());

        if (ObjectUtil.isNotEmpty(param.getChannelNumber())) {

            for (int x = 1; x <= param.getChannelNumber(); x++) {

                // 4.1、保存通道
                BizGatewayChannel channel = BizGatewayChannel.builder()
                        .channel(String.valueOf(x))
                        .channelType(param.getChannelType())
                        .deviceId(0)
                        .gatewayId(gatewayId)
                        .xposion("0")
                        .yposion("0")
                        .status(0)
                        .createdAt(DateTime.now())
                        .build();
                channelMapper.insert(channel);

                // 4.2、保存通道阀值
                BizThreholdItem threholdItem = BizThreholdItem.builder()
                        .gatewayId(gatewayId)
                        .gatewayChannel(String.valueOf(x))
                        .thresholdValue(param.getChannelThreshold())
                        .build();
                threholdItemMapper.insert(threholdItem);

            }

        }

        //  5、如果是防爆网关（4G铁塔）编码 添加主动发声通道
        if (GatewayTypeCodeConstant.EXPLOSION_PROOF_GATEWAY_CODE.equals(param.getTypeCode())) {

            BizChannelType channelType = channelTypeMapper.selectOne(new LambdaUpdateWrapper<BizChannelType>()
                    .eq(BizChannelType::getCode, GatewayTypeCodeConstant.ACOUSTIC_SOUNDER_CODE).last("limit 1"));

            if (ObjectUtil.isNotEmpty(channelType)) {
                // 保存通道
                BizGatewayChannel channel = BizGatewayChannel.builder()
                        .channel("0")
                        .channelType(channelType.getId())
                        .deviceId(0)
                        .gatewayId(gatewayId)
                        .xposion("0")
                        .yposion("0")
                        .status(0)
                        .installLocation("0")
                        .createdAt(DateTime.now())
                        .build();
                channelMapper.insert(channel);
            }

        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(BizGatewayParam param) {

        BizGateway gateway = this.getById(param.getId());

        // 1、检查网关是否存在
        if (ObjectUtil.isEmpty(gateway)) {
            log.warn("网关不存在，网关主键为：{}", param.getId());
            throw new ServiceException(GatewayExceptionEnum.NOT_EXIST);
        }

        // 2、删除网关对应的通道
        channelMapper.delete(new LambdaUpdateWrapper<BizGatewayChannel>().eq(BizGatewayChannel::getGatewayId, gateway.getId()));

        // 3、删除网关对应的通道阀值
        threholdItemMapper.delete(new LambdaUpdateWrapper<BizThreholdItem>().eq(BizThreholdItem::getGatewayId, gateway.getId()));

        // 4、删除网关对应的采集时间调度删除
        scheduleMapper.delete(new LambdaUpdateWrapper<BizGatewaySchedule>().eq(BizGatewaySchedule::getGatewayId, gateway.getId()));

        // 5、删除网关对应的8路采集器配置
        collectorConfigMapper.delete(new LambdaUpdateWrapper<BizCollectorConfig>().eq(BizCollectorConfig::getGatewayId, gateway.getId()));

        // 6、删除网关对应的配置信息
        gatewayConfigService.remove(new LambdaUpdateWrapper<BizGatewayConfig>().eq(BizGatewayConfig::getGatewayId, gateway.getId()));

        // 7、删除网关
        removeById(gateway);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void edit(BizGatewayParam param) {

        // 1、检查编码是否存在
        if (count(new LambdaQueryWrapper<BizGateway>().ne(BizGateway::getId, param.getId())
                .eq(BizGateway::getGatewayCode, param.getGatewayCode())) > 0) {
            log.warn("网关编号已存在，网关编号为：{}", param.getGatewayCode());
            throw new ServiceException(GatewayExceptionEnum.GATEWAY_CODE_EXIST);
        }

        // 2、检查关联站点是否存在
        BizStation station = stationMapper.selectById(param.getStationId());
        if (ObjectUtil.isEmpty(station)) {
            log.warn("关联站点不存在，站点主键为：{}", param.getStationId());
            throw new ServiceException(GatewayExceptionEnum.STATION_NOT_EXIST);
        }

        // 查询网关
        BizGateway gateway = this.queryBizGateway(param);
        param.setUpdatedAt(DateUtil.now());

        // 修改网关场景配置
        if (ObjectUtil.isEmpty(gateway.getSceneId()) || !gateway.getSceneId().equals(param.getSceneId())) {
            // 当前网关关联场景发生变化，
            // 1、删除所有网关配置
            gatewayConfigService.remove(new LambdaQueryWrapper<BizGatewayConfig>().eq(BizGatewayConfig::getGatewayId, gateway.getId()));
            // 2、初始化网关配置
            this.initGatewayConfig(gateway.getId(), param.getSceneId());
        }

        this.updateById(BeanUtil.toBean(param, BizGateway.class));

        // 处理声卡相关参数
        if (ObjectUtil.isNotEmpty(param.getSoundCardId())) {
            updateSoundCardConfig(param.getSoundCardId(), gateway.getId());
        }

        // 下发任务，通知采集端更新配置
        List<Integer> gatewayIds = new ArrayList<>();
        gatewayIds.add(gateway.getId());
        taskService.add(GatewayTaskTypeConstant.UPDATE_CONFIG, gatewayIds, null);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void editGateway(BizGatewayParam param) {

        // 查询网关
        BizGateway gateway = this.queryBizGateway(param);
        param.setUpdatedAt(DateUtil.now());

        if (ObjectUtil.isEmpty(gateway.getSceneId()) || gateway.getSceneId().longValue() != param.getSceneId().longValue()) {
            // 当前网关关联场景发生变化
            // 1、删除所有网关配置
            gatewayConfigService.remove(new LambdaQueryWrapper<BizGatewayConfig>().eq(BizGatewayConfig::getGatewayId, gateway.getId()));
            // 2、初始化网关配置
            this.initGatewayConfig(gateway.getId(), param.getSceneId());
        }

        this.updateById(BeanUtil.toBean(param, BizGateway.class));
        Integer gatewayId = gateway.getId();

        // 3、对网关进行同名查重
        if (count(new LambdaUpdateWrapper<BizGateway>()
                .eq(BizGateway::getGatewayName, param.getGatewayName())
                .eq(BizGateway::getSceneId, gateway.getSceneId())
                .ne(BizGateway::getId, gateway.getId())) > 0) {
            log.warn("同一站点下相同名称的网关已存在，站点主键为：{},网关名称为：{}", gateway.getStationId(), param.getGatewayName());
            throw new ServiceException(GatewayExceptionEnum.SAME_STATION_NAME_GATEWAY_EXIST);
        }

        // 删除通道
        channelMapper.delete(new LambdaUpdateWrapper<BizGatewayChannel>().eq(BizGatewayChannel::getGatewayId, gatewayId));

        // 删除通道阀值
        threholdItemMapper.delete(new LambdaUpdateWrapper<BizThreholdItem>().eq(BizThreholdItem::getGatewayId, gatewayId));

        if (ObjectUtil.isNotEmpty(param.getChannelNumber())) {

            for (int x = 1; x <= param.getChannelNumber(); x++) {

                // 保存通道
                BizGatewayChannel channel = BizGatewayChannel.builder()
                        .channel(String.valueOf(x))
                        .channelType(param.getChannelType())
                        .deviceId(0)
                        .gatewayId(gatewayId)
                        .xposion("0")
                        .yposion("0")
                        .status(0)
                        .installLocation("0")
                        .createdAt(DateTime.now())
                        .build();
                channelMapper.insert(channel);

                // 保存通道阀值
                BizThreholdItem threholdItem = BizThreholdItem.builder()
                        .gatewayId(gatewayId)
                        .gatewayChannel(String.valueOf(x))
                        .thresholdValue(param.getChannelThreshold())
                        .build();
                threholdItemMapper.insert(threholdItem);

            }

        }

        //  防爆网关（4G铁塔）编码 添加主动发声通道
        if (GatewayTypeCodeConstant.EXPLOSION_PROOF_GATEWAY_CODE.equals(param.getTypeCode())) {

            BizChannelType channelType = channelTypeMapper.selectOne(new LambdaUpdateWrapper<BizChannelType>()
                    .eq(BizChannelType::getCode, GatewayTypeCodeConstant.ACOUSTIC_SOUNDER_CODE).last("limit 1"));

            if (ObjectUtil.isNotEmpty(channelType)) {
                // 保存通道
                BizGatewayChannel channel = BizGatewayChannel.builder()
                        .channel("0")
                        .channelType(channelType.getId())
                        .deviceId(0)
                        .gatewayId(gatewayId)
                        .xposion("0")
                        .yposion("0")
                        .status(0)
                        .createdAt(DateTime.now())
                        .build();
                channelMapper.insert(channel);
            }

        }

        // 处理声卡相关参数
        if (ObjectUtil.isNotEmpty(param.getSoundCardId())) {
            updateSoundCardConfig(param.getSoundCardId(), gatewayId);
        }

        // 下发任务，通知采集端更新配置
        List<Integer> gatewayIds = new ArrayList<>();
        gatewayIds.add(gateway.getId());
        taskService.add(GatewayTaskTypeConstant.UPDATE_CONFIG, gatewayIds, null);

    }

    /**
     * 私有方法： 初始化网关配置
     *
     * @param gatewayId 网关主键
     * @param sceneId   场景主键
     */
    private void initGatewayConfig(Integer gatewayId, Long sceneId) {

        // 解决采集器初始化网关时没有场景ID问题，在这里需要判断
        if (ObjectUtil.isEmpty(sceneId)) {
            return;
        }

        // 1、查询场景对应的网关配置模板主键
        List<GatewaySceneConfig> configList = sceneConfigMapper.selectList(new LambdaQueryWrapper<GatewaySceneConfig>().eq(GatewaySceneConfig::getSceneId, sceneId));

        // 2、查询模板配置。进行写库操作
        if (ObjectUtil.isNotEmpty(configList)) {
            for (GatewaySceneConfig config : configList) {
                BizGatewayConfig cfg = BizGatewayConfig.builder()
                        .gatewayId(gatewayId)
                        .templateId(config.getConfigId())
                        .gatewayConfigCode(config.getConfigCode())
                        .configValue(config.getDefaultValue())
                        .build();
                gatewayConfigService.save(cfg);
            }
        }
    }

    @Override
    public void editByGatewayCode(String deviceCode) {
        LambdaUpdateWrapper<BizGateway> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(BizGateway::getGatewayCode, deviceCode);
        BizGateway bizGateway = new BizGateway();
        bizGateway.setUpdatedAt(DateUtil.date());
        bizGateway.setOnlineStatus(1);
        bizGateway.setStatus(1);
        baseMapper.update(bizGateway, updateWrapper);
    }

    @Override
    public BizGateway gatewayByGatewayCode(BizGatewayParam bizGatewayParam) {
        // 构造条件
        LambdaQueryWrapper<BizGateway> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(BizGateway::getGatewayCode, bizGatewayParam.getGatewayCode());
        // 查询分页结果
        return this.getOne(queryWrapper);
    }

    @Override
    public List<BizGateway> offDutyList() {
        String format = DateUtil.now();
        return this.baseMapper.offDutyList(format);
    }

    @Override
    public List<BizGatewayResult> getListAndChannel(LambdaQueryWrapper<BizGateway> queryWrapper) {
        return this.baseMapper.getListAndChannel(queryWrapper);
    }

    @Override
    public List<GatewayChannelStatus> getGatewayChannelStatus() {
        return this.baseMapper.getGatewayChannelStatus();
    }

    @Override
    public void changeSwitch(BizGatewayParam bizGatewayParam) {
        Integer id = bizGatewayParam.getId();
        Integer aSwitch = bizGatewayParam.getDataReportingSwitch();

        LambdaUpdateWrapper<BizGateway> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .eq(BizGateway::getId, id)
                .set(BizGateway::getDataReportingSwitch, aSwitch)
                // 开启时更新数据上报开启时间
                .set(GatewayDataReportStatusConstant.ON.equals(aSwitch), BizGateway::getDataReportOpenTime, DateTime.now())
                // 关闭时将数据上报开启时间置空
                .set(GatewayDataReportStatusConstant.OFF.equals(aSwitch), BizGateway::getDataReportOpenTime, null);
        boolean update = this.update(updateWrapper);
        if (!update) {
            throw new ServiceException(500, "数据上报操作失败");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void batchChangeDataReportStatus(BizGatewayParam param) {

        BizStation station = stationMapper.selectById(param.getStationId());
        if (ObjectUtil.isEmpty(station)) {
            log.warn("关联站点不存在,站点主键为：{}", param.getStationId());
            throw new ServiceException(GatewayExceptionEnum.STATION_NOT_EXIST);
        }

        Integer aSwitch = GatewayDataReportStatusConstant.ON.equals(param.getDataReportingSwitch()) ? GatewayDataReportStatusConstant.ON : GatewayDataReportStatusConstant.OFF;
        // 更新数据
        update(null, new LambdaUpdateWrapper<BizGateway>().eq(BizGateway::getStationId, param.getStationId())
                .set(BizGateway::getDataReportingSwitch, aSwitch)
                .set(GatewayDataReportStatusConstant.OFF.equals(aSwitch), BizGateway::getDataReportOpenTime, null)
                .set(GatewayDataReportStatusConstant.ON.equals(aSwitch), BizGateway::getDataReportOpenTime, DateTime.now()));

    }

    @Override
    public PageResult<BizGateway> initGatewayPage(BizGatewayParam bizGatewayParam) {
        // 构造条件
        LambdaQueryWrapper<BizGateway> queryWrapper = new LambdaQueryWrapper<>();

        queryWrapper.isNull(BizGateway::getStationId);
        if (ObjectUtil.isNotNull(bizGatewayParam)) {
            if (ObjectUtil.isNotEmpty(bizGatewayParam.getGatewayCode())) {
                queryWrapper.eq(BizGateway::getGatewayCode, bizGatewayParam.getGatewayCode());
            }
        }
        // 查询分页结果
        return new PageResult<>(this.page(PageFactory.defaultPage(), queryWrapper));
    }

    @Override
    public BizGatewayParam detail(BizGatewayParam bizGatewayParam) {
        return this.queryBizGatewayParam(bizGatewayParam);
    }

    @Override
    public void changeStatus(BizGatewayParam bizGatewayParam) {
        Integer id = bizGatewayParam.getId();
        Integer status = bizGatewayParam.getStatus();

        LambdaUpdateWrapper<BizGateway> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper
                .eq(BizGateway::getId, id)
                .set(BizGateway::getStatus, status);
        boolean update = this.update(updateWrapper);
        if (!update) {
            throw new ServiceException(StatusExceptionEnum.UPDATE_STATUS_ERROR);
        }
    }

    @Override
    public Map<String, Object> getConfig(BizGatewayParam param) {
        Map<String, Object> cfgMap = new HashMap<>();
        // 查询网关的配置参数
        List<BizGatewayConfig> cfgList = gatewayConfigService.list(new LambdaQueryWrapper<BizGatewayConfig>().eq(BizGatewayConfig::getGatewayId, param.getId()));
        if (ObjectUtil.isNotEmpty(cfgList)) {
            for (BizGatewayConfig cfg : cfgList) {
                cfgMap.put(cfg.getGatewayConfigCode(), cfg.getConfigValue());
            }
        }
        return cfgMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateConfig(Map<String, Object> cfg) {

        // 取得网关Id
        Integer gatewayId = Integer.parseInt(cfg.get("id").toString());

        Set<Map.Entry<String, Object>> entries = cfg.entrySet();
        for (Map.Entry<String, Object> entry : entries) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (!"id".equals(key)) {

                // 查询对应的配置
                BizGatewayConfig config = gatewayConfigService.getOne(new LambdaQueryWrapper<BizGatewayConfig>()
                        .eq(BizGatewayConfig::getGatewayId, gatewayId)
                        .eq(BizGatewayConfig::getGatewayConfigCode, key).last("limit 1"));
                if (ObjectUtil.isEmpty(config)) {
                    continue;
                }

                if (String.valueOf(value).equals(config.getConfigValue())) {
                    continue;
                }

                // 查询关联的网关配置模板
                BizGatewayConfigTemplate template = configTemplateMapper.selectOne(new LambdaQueryWrapper<BizGatewayConfigTemplate>().eq(BizGatewayConfigTemplate::getCode, key).last("limit 1"));
                if (ObjectUtil.isEmpty(template)) {
                    continue;
                }

                //下发更新光纤侦听位置任务
                if (key.equals("opticalListeningLocation") && !config.getConfigValue().equals(value)) {
                    Map<String, Object> map = new HashMap<>();
                    map.put("opticalListeningLocation", value);
                    List<Integer> gatewayIds = new ArrayList<>();
                    gatewayIds.add(gatewayId);
                    taskService.add(GatewayTaskTypeConstant.SYNC_OPTICAL_LISTENING_LOCATION, gatewayIds, JSONUtil.toJsonStr(map));
                }

                // 验证value

                // 更新数据
                config.setConfigValue(String.valueOf(value));
                gatewayConfigService.updateById(config);

            }

        }

    }

    @Override
    public int getCountByGatewayCode(String gatewayCode) {
        QueryWrapper<BizGateway> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("gateway_code", gatewayCode);
        int count = this.count(queryWrapper);
        return count;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String importGateway(GatewayImportParam importParam) {

        // 记录所属站点ID
        Integer stationId = importParam.getStationId();

        // 校验并读取文件数据
        List<GatewayImportParam> params = this.validAndReadFile(importParam.getFileId());

        // 存放网关信息
        List<BizGateway> gateways = new ArrayList<>();

        for (GatewayImportParam param : params) {

            // 1、检查同名网关是否存在
            if (this.count(new LambdaQueryWrapper<BizGateway>().eq(BizGateway::getGatewayName, param.getGatewayName())) > 0) {
                throw new ServiceException(StrFormatter.format("名称为{}的网关已存在", param.getGatewayName()));
            }

            // 2、查询网关类型
            BizGatewayType gatewayType = gatewayTypeMapper.selectOne(new LambdaQueryWrapper<BizGatewayType>()
                    .eq(BizGatewayType::getModelName, param.getTypeName()).last("limit 1"));
            if (ObjectUtil.isEmpty(gatewayType)) {
                throw new ServiceException(StrFormatter.format("名称为{}的网关类型不存在", param.getTypeName()));
            }

            // 3、查询配置场景
            GatewayScene scene = sceneService.getOne(new LambdaQueryWrapper<GatewayScene>().eq(GatewayScene::getSceneName, param.getSceneName()).last("limit 1"));
            if (ObjectUtil.isEmpty(scene)) {
                throw new ServiceException(StrFormatter.format("名称为{}的配置场景不存在", param.getSceneName()));
            }

            // 4、查询传感器类型
            BizChannelType channelType = null;
            if (param.getSensorType().contains("|")) {
                String[] arr = param.getSensorType().split("\\|");
                channelType = channelTypeMapper.selectOne(new LambdaQueryWrapper<BizChannelType>().eq(BizChannelType::getCode, arr[1].trim()).last("limit 1"));
            }
            if (ObjectUtil.isEmpty(channelType)) {
                throw new ServiceException(StrFormatter.format("名称为{}的传感器类型不存在", param.getSensorType()));
            }

            // 5、保存网关
            BizGateway gateway = BizGateway.builder()
                    .gatewayName(param.getGatewayName())
                    .gatewayCode(param.getGatewayCode())
                    .createdAt(DateTime.now())
                    .stationId(stationId)
                    .status(GatewayStatusContant.ENABLE)
                    .onlineStatus(GatewayOnlineStatusConstant.OFF_LINE)
                    .dataReportingSwitch(DataReportingConstant.ON)
                    .sceneId(scene.getId())
                    .typeCode(gatewayType.getCode())
                    .build();
            this.save(gateway);

            // 6、初始化网关配置
            this.initGatewayConfig(gateway.getId(), scene.getId());

            // 7、保存通道信息
            for (int x = 1; x <= Integer.parseInt(param.getChannelNum()); x++) {

                // 保存网关通道信息
                BizGatewayChannel channel = BizGatewayChannel.builder()
                        .channel(String.valueOf(x))
                        .gatewayId(gateway.getId())
                        .status(1)
                        .channelType(channelType.getId())
                        .build();
                gatewayChannelMapper.insert(channel);

                // 保存阀值
                BizThreholdItem threholdItem = BizThreholdItem.builder()
                        .gatewayId(gateway.getId())
                        .gatewayChannel(String.valueOf(x))
                        .thresholdValue(param.getThreshold())
                        .build();
                threholdItemMapper.insert(threholdItem);

            }

        }

        return StrFormatter.format("操作成功，共导入：{}条数据", gateways.size());

    }

    @Override
    public GatewayGrantInfoResult queryGrantInfo() {

        GatewayGrantInfoResult result = GatewayGrantInfoResult.builder().build();

        String projectRes = HttpClientUtil.doGet(HttpClientServerConstant.OA_SERVER_API_URL + "/authProjectManagement/list");
        String partyRes = HttpClientUtil.doGet(HttpClientServerConstant.OA_SERVER_API_URL + "/authPartyManagement/list");
        String typeRes = HttpClientUtil.doGet(HttpClientServerConstant.OA_SERVER_API_URL + "/sysDictType/dropDown?code=authType");
        String deviceTypeRes = HttpClientUtil.doGet(HttpClientServerConstant.OA_SERVER_API_URL + "/deviceType/list");

        List<GatewayGrantInfoItemResult> projectList = null;
        List<GatewayGrantInfoItemResult> partyList = null;
        List<GatewayGrantInfoItemResult> grantTypeList = null;
        List<GatewayGrantInfoItemResult> grantDeviceTypeList = null;


        // 处理项目列表
        if (ObjectUtil.isNotEmpty(projectRes)) {
            JSONObject jsonObject = JSON.parseObject(projectRes);
            if (jsonObject.getBoolean("success")) {
                // 表示请求成功
                JSONArray rows = jsonObject.getJSONArray("data");
                if (ObjectUtil.isNotEmpty(rows) && rows.size() > 0) {
                    for (int x = 0; x < rows.size(); x++) {
                        JSONObject obj = rows.getJSONObject(x);
                        GatewayGrantInfoItemResult itemResult = GatewayGrantInfoItemResult.builder()
                                .id(obj.getLong("id"))
                                .name(obj.getString("projectName"))
                                .build();
                        if (projectList == null) {
                            projectList = new ArrayList<>();
                        }
                        projectList.add(itemResult);

                    }
                }
            }
        }

        // 处理甲方单位
        if (ObjectUtil.isNotEmpty(partyRes)) {
            JSONObject jsonObject = JSON.parseObject(partyRes);
            if (jsonObject.getBoolean("success")) {
                // 表示请求成功
                JSONArray rows = jsonObject.getJSONArray("data");
                if (ObjectUtil.isNotEmpty(rows) && rows.size() > 0) {
                    for (int x = 0; x < rows.size(); x++) {
                        JSONObject obj = rows.getJSONObject(x);
                        GatewayGrantInfoItemResult itemResult = GatewayGrantInfoItemResult.builder()
                                .id(obj.getLong("id"))
                                .name(obj.getString("unit"))
                                .build();
                        if (partyList == null) {
                            partyList = new ArrayList<>();
                        }
                        partyList.add(itemResult);
                    }
                }
            }
        }

        // 处理授权类型
        if (ObjectUtil.isNotEmpty(typeRes)) {
            JSONObject jsonObject = JSON.parseObject(typeRes);
            if (jsonObject.getBoolean("success")) {
                // 表示请求成功
                JSONArray rows = jsonObject.getJSONArray("data");
                if (ObjectUtil.isNotEmpty(rows) && rows.size() > 0) {
                    for (int x = 0; x < rows.size(); x++) {
                        JSONObject obj = rows.getJSONObject(x);
                        GatewayGrantInfoItemResult itemResult = GatewayGrantInfoItemResult.builder()
                                .id(obj.getLong("code"))
                                .name(obj.getString("value"))
                                .build();
                        if (grantTypeList == null) {
                            grantTypeList = new ArrayList<>();
                        }
                        grantTypeList.add(itemResult);
                    }
                }
            }
        }

        // 处理授权设备类型
        if (ObjectUtil.isNotEmpty(deviceTypeRes)) {
            JSONObject jsonObject = JSON.parseObject(deviceTypeRes);
            if (jsonObject.getBoolean("success")) {
                // 表示请求成功
                JSONArray rows = jsonObject.getJSONArray("data");
                if (ObjectUtil.isNotEmpty(rows) && rows.size() > 0) {
                    for (int x = 0; x < rows.size(); x++) {
                        JSONObject obj = rows.getJSONObject(x);
                        GatewayGrantInfoItemResult itemResult = GatewayGrantInfoItemResult.builder()
                                .id(obj.getLong("id"))
                                .name(obj.getString("deviceName"))
                                .build();
                        if (grantDeviceTypeList == null) {
                            grantDeviceTypeList = new ArrayList<>();
                        }
                        grantDeviceTypeList.add(itemResult);

                    }
                }
            }
        }

        result.setProjects(projectList);
        result.setParties(partyList);
        result.setGrantTypes(grantTypeList);
        result.setGrantDeviceTypes(grantDeviceTypeList);

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void syncGatewayGrant() {

        // 查询所有待审核状态的网关
        List<BizGateway> gatewayList = list(new LambdaQueryWrapper<BizGateway>().eq(BizGateway::getOnlineStatus, GatewayOnlineStatusConstant.ON_LINE).isNull(BizGateway::getStationId));

        if (ObjectUtil.isEmpty(gatewayList)) {
            log.warn("没有在线的未绑定的的网关");
            throw new ServiceException(GatewayExceptionEnum.NO_WAIT_AUDIT_GATEWAY_LIST);
        }

        StringBuffer codesBuf = new StringBuffer();
        for (BizGateway gateway : gatewayList) {
            codesBuf.append(gateway.getGatewayCode()).append(",");
        }

        // 删除最后一个逗号
        if (codesBuf.toString().endsWith(",")) {
            codesBuf.deleteCharAt(codesBuf.length() - 1);
        }

        Map<String, String> dataMap = new HashMap<>();
        dataMap.put("deviceCodeList", codesBuf.toString());
        String res = HttpClientUtil.doPost(HttpClientServerConstant.OA_SERVER_API_URL + "/applicationRecord/getStatusList", dataMap);
        JSONObject json = JSON.parseObject(res);

        if (json.getBoolean("success")) {
            log.info(">>>  同步授权申请成功");
            JSONArray rows = json.getJSONArray("data");
            if (ObjectUtil.isNotEmpty(rows) && rows.size() > 0) {

                List<BizGateway> gateways = new ArrayList<>();

                for (int x = 0; x < rows.size(); x++) {

                    JSONObject obj = rows.getJSONObject(x);
                    String authorizationStatus = obj.getString("authorizationStatus");
                    String deviceCode = obj.getString("deviceCode");
                    String authorizedUrl = obj.getString("authorizedUrl");

                    if (GatewayGrantStatusConstant.SERVER_GRANT_SUCCESS.equals(authorizationStatus)) {
                        // 授权成功，需要修改当前网关的授权状态并下发任务通知采集端
                        BizGateway gateway = getOne(new LambdaUpdateWrapper<BizGateway>().eq(BizGateway::getGatewayCode, deviceCode).last("limit 1"));
                        if (ObjectUtil.isNotEmpty(gateway)) {
                            // 更新网关最新状态
                            gateway.setGrantStatus(GatewayGrantStatusConstant.AUDIT_SUCCESS);
                            gateways.add(gateway);
                            Map<String, Object> taskMap = new HashMap<>();
                            taskMap.put("authorizedUrl", HttpClientServerConstant.OA_GRANT_FILE_DOWNLOAD_URL + authorizedUrl);
                            List<Integer> gatewayIds = new ArrayList<>();
                            gatewayIds.add(gateway.getId());
                            // 下发任务通知采集端
                            taskService.add(GatewayTaskTypeConstant.SYNC_GRANT, gatewayIds, JSONUtil.toJsonStr(taskMap));
                            log.info(">>> 授权成功，网关的deviceCode为{}", deviceCode);
                        }
                    }

                }

                saveOrUpdateBatch(gateways, 100);

            }
        } else {
            log.info(">>>  同步授权申请失败");
            throw new ServiceException(GatewayExceptionEnum.SYNC_GRANT_STATUS_FAILED);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void batchAddApplicationRecord(ApplicationRecordParam param) {

        StringBuffer codesBuf = new StringBuffer();
        for (String code : param.getDeviceCodeList()) {
            codesBuf.append(code).append(",");
        }

        // 删除最后一个逗号
        if (codesBuf.toString().endsWith(",")) {
            codesBuf.deleteCharAt(codesBuf.length() - 1);
        }

        Map<String, String> data = new HashMap<>();
        data.put("projectName", param.getProjectName().toString());
        data.put("unitName", param.getUnitName().toString());
        data.put("region", param.getRegion());
        data.put("agent", param.getAgent());
        data.put("authorizedTime", param.getAuthorizedTime().toString());
        data.put("type", param.getType().toString());
        data.put("authorizedDeviceType", param.getAuthorizedDeviceType().toString());
        data.put("remark", param.getRemark());
        data.put("deviceCodeList", codesBuf.toString());

        String res = HttpClientUtil.doPost(HttpClientServerConstant.OA_SERVER_API_URL + "/applicationRecord/saveBatch", data);
        JSONObject json = JSON.parseObject(res);

        if (!json.getBoolean("success")) {
            log.info(">>>  批量授权申请失败");
            throw new ServiceException(GatewayExceptionEnum.BATCH_APPLICATION_GRANT_FAILED);
        } else {
            log.info(">>>  批量授权申请成功");
            // 修改申请授权状态
            List<String> codeList = param.getDeviceCodeList();
            if (ObjectUtil.isNotEmpty(codeList)) {
                List<BizGateway> gatewayList = new ArrayList<>();
                for (String code : codeList) {
                    BizGateway gateway = getOne(new LambdaUpdateWrapper<BizGateway>().eq(BizGateway::getGatewayCode, code).last("limit 1"));
                    // 授权状态修改为待审核
                    gateway.setGrantStatus(GatewayGrantStatusConstant.WAIT_AUDIT);
//                    updateById(gateway);
                    gatewayList.add(gateway);
                }
                saveOrUpdateBatch(gatewayList, 100);
            }
        }

    }

    @Override
    public DeviceStatusNumberResult getDeviceOnlineNumber(Integer stationId) {

        LambdaQueryWrapper<BizDevice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(BizDevice::getStationId,stationId);
        return this.baseMapper.getDeviceOnlineNumber(wrapper);
    }

    /**
     * 获取采集设备
     *
     * @author ssy
     * @since 2021/09/14 11:47
     */
    private BizGateway queryBizGateway(BizGatewayParam param) {
        BizGateway bizGateway = this.getById(param.getId());
        if (ObjectUtil.isEmpty(bizGateway)) {
            log.warn("网关不存在，网关主键为：{}", param.getId());
            throw new ServiceException(GatewayExceptionEnum.NOT_EXIST);
        }
        return bizGateway;
    }

    private BizGatewayParam queryBizGatewayParam(BizGatewayParam bizGatewayParam) {
        BizGatewayParam bizGateway = this.baseMapper.getById(bizGatewayParam.getId());
        return bizGateway;
    }

    /**
     * 验证并读取文件信息
     *
     * @param fileId 导入文件的主键
     * @return
     */
    private List<GatewayImportParam> validAndReadFile(Long fileId) {

        // 获取导入文件的信息
        SysFileInfo fileInfo = fileInfoService.getById(fileId);
        if (ObjectUtil.isNull(fileInfo)) {
            throw new ServiceException("导入文件不存在");
        }
        // 判断文件是否存在
        String filePath = this.getUploadPath() + "/" + fileInfo.getFileBucket() + "/" + fileInfo.getFileObjectName();
        File file = new FileSystemResource(filePath).getFile();
        if (!file.exists()) {
            throw new ServiceException("导入文件不存在");
        }

        // 读取文件内容
        List<GatewayImportParam> params = EasyExcel.read(file, GatewayImportParam.class, new GatewayImportListener())
                .sheet().sheetNo(0).doReadSync();

        // 判断是否存在数据
        if (CollectionUtil.isEmpty(params)) {
            throw new ServiceException("未读取到文件数据");
        }

        return params;
    }

    /**
     * 获取上传路径
     *
     * @return
     */
    private String getUploadPath() {
        //动态获取环境变量的值；Windows 10
        String property = System.getProperties().getProperty("os.name");

        //获取音频文件
        String path;
        if (property.contains("Windows")) {
            path = ConstantContextHolder.getDefaultFileUploadPathForWindows();
        } else {
            path = ConstantContextHolder.getDefaultFileUploadPathForLinux();
        }
        return path;
    }

    /**
     * 私有方法：更新声卡相关配置
     */
    private void updateSoundCardConfig(Long soundCardId, Integer gatewayId) {

        SoundCard soundCard = soundCardService.getById(soundCardId);

        // 修改声卡识别名称
        BizGatewayConfig nameCfg = gatewayConfigService.getOne(new LambdaUpdateWrapper<BizGatewayConfig>()
                .eq(BizGatewayConfig::getGatewayId, gatewayId)
                .eq(BizGatewayConfig::getGatewayConfigCode, GatewayConfigConstant.SOUND_CARD_NAME_CODE));

        if (ObjectUtil.isNotEmpty(nameCfg)) {
            nameCfg.setConfigValue(soundCard.getDistinguishCode());
            gatewayConfigService.updateById(nameCfg);
        }

        // 修改声卡通道数量
        BizGatewayConfig numCfg = gatewayConfigService.getOne(new LambdaUpdateWrapper<BizGatewayConfig>()
                .eq(BizGatewayConfig::getGatewayId, gatewayId)
                .eq(BizGatewayConfig::getGatewayConfigCode, GatewayConfigConstant.SOUND_CARD_CHANNEL_NUM_COED));

        if (ObjectUtil.isNotEmpty(numCfg)) {
            numCfg.setConfigValue(soundCard.getVocalTractNumber().toString());
            gatewayConfigService.updateById(numCfg);
        }

    }

}
